<template>
  <textarea
    v-if="$attrs.type === 'textarea'"
    v-model="val"
    class="form-control"
    :class="{ 'is-invalid': error }"
    v-bind="$attrs"
    autocomplete="new-password"
    @blur="handleBlur"
    @input="handleInput"
  />
  <input
    v-else
    v-model="val"
    class="form-control"
    :class="{ 'is-invalid': error }"
    v-bind="$attrs"
    autocomplete="new-password"
    @blur="handleBlur"
    @input="handleInput"
  />
  <div class="invalid-feedback">
    {{ message }}
  </div>
</template>
<script lang="ts">
import { defineComponent, reactive, toRefs, PropType, computed } from 'vue'
import { TRulesProp, ERuleType, IRuleProp, TValidateFun } from '@/types/index'
import bus from '@/plugins/bus'
const emailReg = /^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+$/
export default defineComponent({
  name: 'ValidateInput',
  props: {
    rules: {
      type: Array as PropType<TRulesProp>
    },
    modelValue: String
  },
  setup(props, { emit }) {
    const state = reactive({
      val: computed({
        get: () => props.modelValue || '',
        set: (val) => {
          emit('update:modelValue', val)
        }
      }),
      error: false,
      message: ''
    })
    // input 事件
    const handleInput = (e: InputEvent) => {
      validateInput(e.type)
    }
    // blur 事件
    const handleBlur = (e: InputEvent) => {
      validateInput(e.type)
    }
    // 规则校验
    const checkRule = (rule: IRuleProp) => {
      state.message = rule.message
      let passed = false
      switch (rule.type) {
        case ERuleType.REQUIRED:
          passed = state.val.trim() !== ''
          break
        case ERuleType.EMAIL:
          passed = emailReg.test(state.val)
          break
        case ERuleType.RANGE:
          if (rule.min && rule.max) {
            passed =
              state.val.trim().length >= rule.min &&
              state.val.trim().length <= rule.max
          } else if (rule.min) {
            passed = state.val.trim().length >= rule.min
          } else if (rule.max) {
            passed = state.val.trim().length <= rule.max
          }
          break
        case ERuleType.VALIDATOR:
          passed = rule.validator ? rule.validator() : true
          break
        default:
          break
      }
      return passed
    }
    // input 校验
    const validateInput: TValidateFun = (trigger) => {
      if (props.rules) {
        const allPassed = props.rules.every((rule) => {
          if (rule?.trigger === trigger) {
            return checkRule(rule)
          } else if (trigger === 'blur' || !trigger) {
            return checkRule(rule)
          } else {
            return true
          }
        })
        state.error = !allPassed
        return allPassed
      } else {
        return true
      }
    }
    // 清空
    const cleanInput = () => {
      state.val = ''
      state.error = false
      state.message = ''
    }
    // 发送校验函数给ValidateForm
    bus.emit('form-validate', validateInput)
    // 发送清空函数给ValidateForm
    bus.emit('form-clean', cleanInput)
    return {
      ...toRefs(state),
      handleBlur,
      handleInput
    }
  }
})
</script>
